/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package controle;

import br.ufrn.dca.controle.QuanserClient;
import br.ufrn.dca.controle.QuanserClientException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Daniel, Lindemberg, Mauricio, Taeko, Thiago
 */
public class Controlador {
    private String log, servidor, dataString;
    private QuanserClient cliente;
    private int porta, entradaAnalogica, saidaAnalogica;
    private DateFormat dateFormat;
    private Date date;
    private Malha malha;
    private double tensaoMotor;
    
    // Variáveis de controle
    private Sinal sinal;
    private double pv, sp, erro, amplitude, nivelT1, nivelT2, tensaoIdeal;
    
    
    public Controlador(){
        servidor = "localhost"; // IP: 10.13.99.69
        porta = 20081; // 20081 ou 20082
        
        saidaAnalogica = 0;
        entradaAnalogica = 0;
        
        // Por Default, a malha selecionada é aberta
        malha = Malha.ABERTA;
        
        // Formato da data e hora do log.
        dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        date = new Date();
        dataString = dateFormat.format(date);
        
        log = (dataString + " -- Programa Iniciado!\n");
        System.out.println(log);
        try{
            cliente = new QuanserClient("localhost", 20081);
        }catch(QuanserClientException ex){
            
        }
        
    }
    
    // Função para conectar com o servidor
    public void Conectar(String servidor){
        this.servidor = servidor;
        try {
            cliente = new QuanserClient(this.servidor, porta);
            //atualizar();
            setLog("Conexão com o servidor " + this.servidor + " foi bem sucedida!");
        } catch (QuanserClientException ex) {
             setLog("Erro na conexão com o servidor " + this.servidor + "!");
        }
    }
    
    public void setLog(String addLog){
        atualizarHora();
        this.log = log.concat(dataString + " -- " + addLog + "\n");
    }
    
    public void setLogInteiro(String addLog){
        this.log = addLog;
    }
    
    public String getLog(){
        return this.log;
    }
    
    private void atualizarHora(){
        date = new Date();
        dataString = dateFormat.format(date);
    }

    public int getSaida(){
        return saidaAnalogica;
    }
    
    public void setSaida(int saida, boolean selected){
        saidaAnalogica = saida;
        if(selected){
            setLog("Saída analógica " + saida + " selecionada!");
        }else{
            setLog("Saída analógica " + saida + " deselecionada!");
        }
    }
    
    public int getEntrada(){
        return entradaAnalogica;
    }
    
    public void setEntrada(int entradaAnalogica){
        this.entradaAnalogica = entradaAnalogica;
        setLog("Entrada analógica " + entradaAnalogica + " selecionada!");
    }
    
    public void setPorta(int porta){
        this.porta = porta;
        setLog("Porta " + porta + " selecionada!");
    }
    
    public int getPorta(){
        return this.porta;
    }

    /**
     * @return the malhaAberta
     */
    public Malha getMalha() {
        return malha;
    }

    /**
     * @param malhaAberta the malhaAberta to set
     */
    public void setMalha(Malha malha) {
        this.malha = malha;
        if(malha == Malha.ABERTA){
            setLog("Malha Aberta Selecionada!");
        }else{
            setLog("Malha Fechada Selecionada!");
        }
        
    }

    public void setServidor(String servidor) {
        this.servidor = servidor;
        setLog("Servidor " + servidor + " Selecionado");
    }

    public void setSetPoint(double sp) {
        if (sp < 2) {
            this.sp = 2;
            setLog("Set-Point fora dos limites. Valor mínimo selecionado: set-point = " + sp);
        } else if (sp > 28) {
            this.sp = 28;
            setLog("Set-Point fora dos limites. Valor máximo selecionado: set-point = " + sp);
        } else {
            this.sp = sp;
            setLog("Set-Point: " + sp);
        }
        
        final double a1 = 0.0791729767;//diametro do escape de saida
        final double Km = 6.25;//ganho
        final double g = 980.665;//aceleração da gravidade em cm/sec2
        //O cálculo da tensão ideal é realizado segundo a equação:
        //  Vp = a1*raiz(2*g*SP)/Km
        this.tensaoMotor = a1 * Math.sqrt(2 * g * this.sp) / Km;
        
    }

    public void setSinal(Sinal sinal) {
        this.sinal = sinal;
        setLog("Sinal selecionado: " + sinal.toString());
    }

    /**
     * @return the amplitude
     */
    public double getAmplitude() {
        return amplitude;
    }

    /**
     * @param amplitude the amplitude to set
     */
    public void setAmplitude(double amplitude) {
        if(amplitude>0 && amplitude <=3){
            this.amplitude = amplitude;
            setLog("Amplitude " + amplitude + " Selecionada.");
        }else{
            setLog("Valor da amplitude fora dos limites (0 - 3V)!");
        }
        
    }
    
    public double getSinalLido(int porta){
        double lido = 0;
        try {
            lido = cliente.read(porta);
        } catch (QuanserClientException ex) {
            Logger.getLogger(Controlador.class.getName()).log(Level.SEVERE, null, ex);
        }
        return lido;
    }

    /**
     * @return the sinal'
     */
    public Sinal getSinal() {
        return sinal;
    }

    public void escrever(int tensao, double temporizador) throws QuanserClientException{
        cliente.write(tensao, temporizador);
        setLog("Tensão de " + tensao + " escrita na porta " + saidaAnalogica);
    }

    /**
     * @return the nivelT1
     */
    public double getNivelT1() {
        return nivelT1;
    }

    /**
     * @param nivelT1 the nivelT1 to set
     */
    public void setNivelT1(double nivelT1) {
        this.nivelT1 = nivelT1;
    }

    /**
     * @return the erro
     */
    public double getErro() {
        return erro;
    }

    /**
     * @param erro the erro to set
     */
    public void setErro(double erro) {
        this.erro = erro;
    }

    /**
     * @return the sp
     */
    public double getSp() {
        return sp;
    }

    /**
     * @param sp the sp to set
     */
    public void setSp(double sp) {
        this.sp = sp;
    }

    public double ajusteDeNivel(double nivelT1) {
        this.setTensaoMotor(0);
        this.nivelT1 = nivelT1;
        this.erro = this.sp - nivelT1;
        double tensaoMotorAux;
        
        if (erro < -5) {
            tensaoMotorAux = -3.0;
        } else if (erro > 5) {
            tensaoMotorAux = 3.0;
        } else {
            tensaoMotorAux = 0.0207 * Math.pow(this.erro, 3) + 0.0715 * this.erro;
        }

        //testes de segurança
        if (nivelT1 >= 30 && tensaoMotorAux > 0.0) { //FUNÇÃO DESNECESSÁRIA!!
            //caso de transbordo
            //define-se uma tensaõ negativa nos motores para sugar a água em exceço
            tensaoMotorAux = -0.3;
        } else if (nivelT1 >= 27 && tensaoMotorAux > 0.0) {
            //caso quase transbordo
            //desliga-se os motores para evitar que a água chegue a nível crítico
            tensaoMotorAux = 0.0;
        } else if (nivelT1 <= 4 && tensaoMotorAux < 0.0) {
            //caso sucção vazio
            //elev-se a tensão um pouco
            tensaoMotorAux = 0.0;
        } else if (nivelT1 <= 2 && tensaoMotorAux < 0.0) {//FUNÇÃO DESNECESSÁRIA!!!!
            //caso quase-sucção vazia
            //desliga-se os motores para evitar a sucção vazia
            tensaoMotorAux = 0.0;
        }
        this.setTensaoMotor(tensaoMotorAux);
        return tensaoMotorAux;
    }

    /**
     * @return the tensaoMotor
     */
    public double getTensaoMotor() {
        return tensaoMotor;
    }

    /**
     * @param tensaoMotor the tensaoMotor to set
     */
    public void setTensaoMotor(double tensaoMotor) {
        this.tensaoMotor = tensaoMotor;
    }

    private void atualizar() throws QuanserClientException {
        double a = 5.5;//ganho da leitura, converte de tensão para altura
            for (int i = 0; i < 50; i++) {
                cliente.write(0, ajusteDeNivel(cliente.read(0) * a));
                System.out.print(i);
                System.out.print(" ");
                System.out.println(cliente.read(0) * a);
            }
            cliente.write(0, 0);
    }

}